package com.dkd.manage.service.impl;

import java.util.Date;
import java.util.List;

import com.dkd.common.exception.ServiceException;
import com.dkd.common.utils.SecurityUtils;
import com.dkd.manage.domain.Emp;
import com.dkd.manage.domain.TaskDetails;
import com.dkd.manage.domain.VendingMachine;
import com.dkd.manage.mapper.EmpMapper;
import com.dkd.manage.mapper.VendingMachineMapper;
import com.dkd.manage.utils.TaskNoGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.dkd.manage.mapper.TaskMapper;
import com.dkd.manage.domain.Task;
import com.dkd.manage.service.ITaskService;

/**
 * 工单Service业务层处理
 *
 * @author dkd
 * @date 2025-11-10
 */
@Service
public class TaskServiceImpl implements ITaskService
{
    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private TaskNoGenerator taskNoGenerator;

    @Autowired
    private VendingMachineMapper vendingMachineMapper;

    @Autowired
    private EmpMapper empMapper;

    /** 工单状态：待处理 */
    private static final int STATUS_PENDING = 0;

    /** 工单状态：进行中 */
    private static final int STATUS_IN_PROGRESS = 1;

    /** 工单状态：已完成 */
    private static final int STATUS_COMPLETED = 2;

    /** 工单状态：已取消 */
    private static final int STATUS_CANCELLED = 3;

    /** 工单类型：投放工单 */
    private static final int TASK_TYPE_DEPLOY = 1;

    /** 工单类型：维修工单 */
    private static final int TASK_TYPE_REPAIR = 2;

    /** 工单类型：补货工单 */
    private static final int TASK_TYPE_SUPPLY = 3;

    /** 工单类型：撤机工单 */
    private static final int TASK_TYPE_WITHDRAW = 4;

    /** 设备状态：运行 */
    private static final int VM_STATUS_RUNNING = 1;

    /** 设备状态：故障 */
    private static final int VM_STATUS_FAULT = 2;

    /**
     * 查询工单
     *
     * @param id 工单主键
     * @return 工单
     */
    @Override
    public Task selectTaskById(Long id)
    {
        return taskMapper.selectTaskById(id);
    }

    /**
     * 根据工单编号查询工单
     *
     * @param taskNo 工单编号
     * @return 工单
     */
    @Override
    public Task selectTaskByTaskNo(String taskNo)
    {
        return taskMapper.selectTaskByTaskNo(taskNo);
    }

    /**
     * 查询工单列表
     *
     * @param task 工单
     * @return 工单
     */
    @Override
    public List<Task> selectTaskList(Task task)
    {
        return taskMapper.selectTaskList(task);
    }

    /**
     * 新增工单（包含完整业务校验）
     *
     * @param task 工单
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertTask(Task task)
    {
        // 1. 校验设备是否存在
        if (task.getDeviceId() == null)
        {
            throw new ServiceException("设备ID不能为空");
        }

        VendingMachine vendingMachine = vendingMachineMapper.selectVendingMachineById(task.getDeviceId());
        if (vendingMachine == null)
        {
            throw new ServiceException("设备不存在，无法创建工单");
        }

        // 2. 校验设备状态与工单类型是否匹配
        validateDeviceStatusAndTaskType(vendingMachine, task.getTaskTypeId());

        // 3. 校验是否存在未完成的同类型工单
        int unfinishedCount = taskMapper.countUnfinishedTaskByDeviceAndType(
            task.getDeviceId(), task.getTaskTypeId(), null);
        if (unfinishedCount > 0)
        {
            throw new ServiceException("该设备存在未完成的同类型工单，无法创建新工单");
        }

        // 4. 校验执行员工是否在设备所属区域
        if (task.getAssigneeId() == null)
        {
            throw new ServiceException("执行人员不能为空");
        }

        Emp emp = empMapper.selectEmpById(task.getAssigneeId());
        if (emp == null)
        {
            throw new ServiceException("执行人员不存在");
        }

        // 校验员工所属区域是否与设备所属区域一致
        if (!vendingMachine.getRegionId().equals(emp.getRegionId()))
        {
            throw new ServiceException(String.format(
                "执行人员所属区域（%s）与设备所属区域（%s）不一致，无法创建工单",
                emp.getRegionName(), vendingMachine.getRegionName()));
        }

        // 5. 生成工单编号（使用Redis）
        String taskNo = taskNoGenerator.generateTaskNo();
        task.setTaskNo(taskNo);

        // 6. 设置冗余字段（从设备信息中获取）
        task.setDeviceCode(vendingMachine.getInnerCode());
        task.setDeviceName(vendingMachine.getNodeName());
        task.setDeviceStatus(vendingMachine.getVmStatus());
        task.setRegionId(vendingMachine.getRegionId());
        task.setRegionName(vendingMachine.getRegionName());

        // 7. 设置冗余字段（从员工信息中获取）
        task.setAssigneeName(emp.getUserName());
        task.setAssigneeRegionId(emp.getRegionId());

        // 8. 设置默认状态为"待处理"
        if (task.getStatus() == null)
        {
            task.setStatus(STATUS_PENDING);
            task.setStatusName("待处理");
        }

        // 9. 设置默认优先级为"中"
        if (task.getPriority() == null)
        {
            task.setPriority(2);
        }

        // 10. 设置创建时间
        task.setCreateTime(new Date());
        task.setCreateBy(SecurityUtils.getUsername());

        // 11. 插入工单主表
        int rows = taskMapper.insertTask(task);

        // 12. 插入工单详情（如果有）
        insertTaskDetails(task);

        return rows;
    }

    /**
     * 修改工单
     *
     * @param task 工单
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateTask(Task task)
    {
        // 如果修改了设备ID或工单类型，需要重新校验
        if (task.getDeviceId() != null && task.getTaskTypeId() != null)
        {
            // 1. 校验设备是否存在
            VendingMachine vendingMachine = vendingMachineMapper.selectVendingMachineById(task.getDeviceId());
            if (vendingMachine == null)
            {
                throw new ServiceException("设备不存在");
            }

            // 2. 校验设备状态与工单类型是否匹配
            validateDeviceStatusAndTaskType(vendingMachine, task.getTaskTypeId());

            // 3. 校验是否存在未完成的同类型工单（排除当前工单）
            int unfinishedCount = taskMapper.countUnfinishedTaskByDeviceAndType(
                task.getDeviceId(), task.getTaskTypeId(), task.getId());
            if (unfinishedCount > 0)
            {
                throw new ServiceException("该设备存在未完成的同类型工单");
            }
        }

        // 如果修改了执行人员，需要重新校验
        if (task.getAssigneeId() != null)
        {
            Emp emp = empMapper.selectEmpById(task.getAssigneeId());
            if (emp == null)
            {
                throw new ServiceException("执行人员不存在");
            }

            // 获取工单关联的设备信息
            Task existingTask = taskMapper.selectTaskById(task.getId());
            if (existingTask != null)
            {
                VendingMachine vendingMachine = vendingMachineMapper.selectVendingMachineById(existingTask.getDeviceId());
                if (vendingMachine != null && !vendingMachine.getRegionId().equals(emp.getRegionId()))
                {
                    throw new ServiceException(String.format(
                        "执行人员所属区域（%s）与设备所属区域（%s）不一致",
                        emp.getRegionName(), vendingMachine.getRegionName()));
                }
            }

            // 更新冗余字段
            task.setAssigneeName(emp.getUserName());
            task.setAssigneeRegionId(emp.getRegionId());
        }

        task.setUpdateTime(new Date());
        task.setUpdateBy(SecurityUtils.getUsername());

        // 先删除工单详情
        taskMapper.deleteTaskDetailsByTaskId(task.getId());

        // 更新工单主表
        int rows = taskMapper.updateTask(task);

        // 重新插入工单详情
        insertTaskDetails(task);

        return rows;
    }

    /**
     * 批量删除工单
     *
     * @param ids 需要删除的工单主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteTaskByIds(Long[] ids)
    {
        taskMapper.deleteTaskDetailsByTaskIds(ids);
        return taskMapper.deleteTaskByIds(ids);
    }

    /**
     * 删除工单信息
     *
     * @param id 工单主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteTaskById(Long id)
    {
        taskMapper.deleteTaskDetailsByTaskId(id);
        return taskMapper.deleteTaskById(id);
    }

    /**
     * 取消工单
     * 只有"待处理"和"进行中"状态的工单可被取消
     *
     * @param id 工单ID
     * @param cancelReason 取消原因
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cancelTask(Long id, String cancelReason)
    {
        // 1. 查询工单信息
        Task task = taskMapper.selectTaskById(id);
        if (task == null)
        {
            throw new ServiceException("工单不存在");
        }

        // 2. 校验工单状态（只有"待处理"和"进行中"状态可被取消）
        if (task.getStatus() != STATUS_PENDING && task.getStatus() != STATUS_IN_PROGRESS)
        {
            String statusName = getStatusName(task.getStatus());
            throw new ServiceException(String.format("工单状态为【%s】，无法取消。只有【待处理】或【进行中】状态的工单可被取消", statusName));
        }

        // 3. 更新工单状态为"已取消"
        Task updateTask = new Task();
        updateTask.setId(id);
        updateTask.setStatus(STATUS_CANCELLED);
        updateTask.setStatusName("已取消");
        updateTask.setCancelReason(cancelReason);
        updateTask.setCancelTime(new Date());
        updateTask.setCancelBy(SecurityUtils.getUsername());
        updateTask.setUpdateTime(new Date());
        updateTask.setUpdateBy(SecurityUtils.getUsername());

        return taskMapper.updateTask(updateTask);
    }

    /**
     * 校验设备状态与工单类型是否匹配
     *
     * @param vendingMachine 设备信息
     * @param taskTypeId 工单类型ID
     * 陈艺文
     */
    private void validateDeviceStatusAndTaskType(VendingMachine vendingMachine, Integer taskTypeId)
    {
        if (taskTypeId == null)
        {
            throw new ServiceException("工单类型不能为空");
        }

        Integer vmStatus = vendingMachine.getVmStatus();

        // 根据工单类型校验设备状态
        switch (taskTypeId)
        {
            case TASK_TYPE_DEPLOY:
                // 投放工单：设备状态无要求（新设备投放）
                break;

            case TASK_TYPE_REPAIR:
                // 维修工单：设备必须是故障状态
                if (vmStatus != VM_STATUS_FAULT)
                {
                    throw new ServiceException("只有故障状态的设备才能创建维修工单");
                }
                break;

            case TASK_TYPE_SUPPLY:
                // 补货工单：设备必须是运行状态
                if (vmStatus != VM_STATUS_RUNNING)
                {
                    throw new ServiceException("只有运行状态的设备才能创建补货工单");
                }
                break;

            case TASK_TYPE_WITHDRAW:
                // 撤机工单：设备状态无要求
                break;

            default:
                throw new ServiceException("不支持的工单类型");
        }
    }

    /**
     * 新增工单详情信息
     *
     * @param task 工单对象
     */
    private void insertTaskDetails(Task task)
    {
        List<TaskDetails> taskDetailsList = task.getTaskDetailsList();
        if (!CollectionUtils.isEmpty(taskDetailsList))
        {
            Long taskId = task.getId();
            for (TaskDetails taskDetails : taskDetailsList)
            {
                taskDetails.setTaskId(taskId);
                taskDetails.setCreateTime(new Date());
                taskDetails.setUpdateTime(new Date());
            }
            taskMapper.batchTaskDetails(taskDetailsList);
        }
    }

    /**
     * 根据状态码获取状态名称
     *
     * @param status 状态码
     * @return 状态名称
     */
    private String getStatusName(Integer status)
    {
        switch (status)
        {
            case STATUS_PENDING:
                return "待处理";
            case STATUS_IN_PROGRESS:
                return "进行中";
            case STATUS_COMPLETED:
                return "已完成";
            case STATUS_CANCELLED:
                return "已取消";
            default:
                return "未知状态";
        }
    }
}
